module super_zeka;

import std.stdio;
import std.random;
import std.string;
import std.range;
import std.conv;
import hakem;

alias std.range.repeat repeat;

class SüperZekaOyunu
{
    dstring tutulan;   // tuttuğumuz sayı
    Hakem hakem;      // kuralları işleten program mantığı

    static const string satırBaşıDüzeni = "%3s: ";
    static const string numarasızSatırBaşı = "   : ";

    this(in dstring geçerliRakamlar, in size_t haneAdedi)
    in {
        assert((haneAdedi >= 1) && (haneAdedi <= geçerliRakamlar.length));

    } out {
        assert(tutulan.length == haneAdedi);

    } body {
        hakem = new Hakem(geçerliRakamlar, haneAdedi);

        dchar[] rakamlar = geçerliRakamlar.dup;
        randomShuffle(rakamlar);
        tutulan = rakamlar[0..haneAdedi].idup;
    }

    dstring tahminiOku(string numaralıSatırBaşı)
    out (sonuç) {
        assert(sonuç.length == tutulan.length);

    } body {
        dstring okunan;
        Hakem.Karar karar;
        bool numaraYazıldı_mı = false;

        string girinti()
        {
            return numaraYazıldı_mı ? numarasızSatırBaşı : numaralıSatırBaşı;
        }

        do {
            write(girinti());
            numaraYazıldı_mı = true;

            okunan = dtext(chomp(readln()));

            if (okunan == "?") {
                // Soru işareti girilince tuttuğumuzu gösteriyoruz
                okunan = tutulan;
                writeln(girinti(), okunan, " tutmuştum");
            }

            karar = hakem.yasal_mı(okunan);
            foreach (mesaj; karar.uyarıMesajları) {
                writeln(girinti(), mesaj);
            }
        } while (!karar.yasal_mı);

        return okunan;
    }

    void oynat()
    {
        // Tutulanı gizli olarak '#' karakterleri ile gösteriyoruz
        writeln(numarasızSatırBaşı, repeat('#', tutulan.length));

        auto sonuç = TahminSonucu(0, 0);

        for (int hamle = 1; sonuç.yeriDeDoğru != tutulan.length; ++hamle) {
            string numaralıSatırBaşı = format(satırBaşıDüzeni, hamle);
            dstring tahmin = tahminiOku(numaralıSatırBaşı);
            sonuç = hakem.karşılaştır(tutulan, tahmin);
            writeln(numarasızSatırBaşı, repeat(' ', tutulan.length), sonuç);
        }
    }
}
